/* eslint-disable no-param-reassign */
import { RuntimeError, debounceAndAsyncMerge } from '@ibiz-template/core';
import {
  ControlController,
  ControllerEvent,
  ControlVO,
  findChildFormDetails,
  FormNotifyState,
  getFormDetailProvider,
  IFormController,
  IFormDetailController,
  IFormDetailProvider,
  IFormEvent,
  IFormState,
  isValueChange,
} from '@ibiz-template/runtime';
import { IDEForm, IDEFormDetail } from '@ibiz/model-core';
import { FormGroupPanelController, FormItemController } from '../form-detail';

/**
 * 表单控制器
 *
 * @author chitanda
 * @date 2022-08-03 11:08:29
 * @export
 * @class FormController
 * @extends {ControlController<T>}
 * @template T
 */
export abstract class FormController<
    T extends IDEForm = IDEForm,
    S extends IFormState = IFormState,
    E extends IFormEvent = IFormEvent,
  >
  extends ControlController<T, S, E>
  implements IFormController<T, S, E>
{
  protected get _evt(): ControllerEvent<IFormEvent> {
    return this.evt;
  }

  /**
   * 所有表单项成员的控制器
   *
   * @author lxm
   * @date 2022-08-24 20:08:07
   * @type {{ [key: string]: IFormDetailController }}
   */
  details: { [key: string]: IFormDetailController } = {};

  /**
   * 所有表单项成员的适配器
   *
   * @author lxm
   * @date 2022-08-24 20:08:07
   * @type {{ [key: string]: IFormDetailProvider }}
   */
  providers: { [key: string]: IFormDetailProvider } = {};

  /**
   * 表单项控制器的集合
   *
   * @author lxm
   * @date 2022-09-05 00:09:52
   * @type {FormItemController[]}
   */
  formItems: FormItemController[] = [];

  /**
   * 表单数据
   *
   * @author chitanda
   * @date 2023-01-04 10:01:46
   * @readonly
   * @type {IData}
   */
  get data(): IData {
    return this.state.data;
  }

  protected initState(): void {
    super.initState();
    this.state.data = new ControlVO();
    this.state.isLoaded = false;
    this.state.processing = false;
    this.state.modified = false;
  }

  /**
   * 通知所有表单成员表单操作过程中的数据变更
   *
   * @author lxm
   * @date 2022-09-20 18:09:40
   * @param {string[]} names
   */
  async dataChangeNotify(names: string[]): Promise<void> {
    // 通知所有成员项去处理成员项相关逻辑
    const values = await Promise.allSettled(
      Object.values(this.details).map(async detail => {
        return detail.dataChangeNotify(names);
      }),
    );
    if (values.find(item => item.status === 'rejected')) {
      ibiz.log.error('dataChangeNotify报错', values);
      throw new RuntimeError('数据变更后有错误');
    }
  }

  /**
   * 表单状态变更通知
   *
   * @author lxm
   * @date 2022-09-20 18:09:07
   */
  formStateNotify(state: FormNotifyState): void {
    Object.values(this.details).forEach(detail => {
      detail.formStateNotify(state);
    });
  }

  /**
   * 初始化
   *
   * @author lxm
   * @date 2022-08-24 20:08:59
   * @protected
   * @returns {*}  {Promise<void>}
   */
  protected async onCreated(): Promise<void> {
    await super.onCreated();
    await this.initDetailControllers();

    // 数据变更通知防抖，且合并参数
    this.dataChangeNotify = debounceAndAsyncMerge(
      this.dataChangeNotify.bind(this),
      (arr1, arr2): [string[]] => {
        return [Array.from(new Set([...arr1[0], ...arr2[0]]))];
      },
      200,
    );
  }

  /**
   * 获取加载草稿额外参数，新建默认值
   * @author lxm
   * @date 2023-04-27 10:32:06
   * @return {*}
   */
  async getDraftParams(): Promise<IData> {
    const result: IData = {};
    await Promise.all(
      this.formItems.map(item => item.setDefaultValue(true, result)),
    );
    return result;
  }

  /**
   * 初始化表单成员控制器
   *
   * @author lxm
   * @date 2022-08-24 21:08:48
   * @protected
   */
  protected async initDetailControllers(
    details: IDEFormDetail[] = this.model.deformPages!,
    form: FormController = this,
    parent: FormGroupPanelController | undefined = undefined,
  ): Promise<void> {
    await Promise.all(
      details.map(async detail => {
        // 生成表单成员控制器
        const detailProvider = await getFormDetailProvider(detail);
        if (!detailProvider) {
          return;
        }
        form.providers[detail.id!] = detailProvider;
        const detailController = await detailProvider.createController(
          detail,
          form,
          parent,
        );
        form.details[detail.id!] = detailController;
        if (detail.detailType === 'FORMITEM') {
          form.formItems.push(detailController as FormItemController);
        }
        // 有子成员的生成子控制器
        const childDetails = findChildFormDetails(detail);
        if (childDetails.length) {
          await this.initDetailControllers(
            childDetails,
            form,
            detailController as FormGroupPanelController,
          );
        }
      }),
    );
  }

  /**
   * 加载
   *
   * @author lxm
   * @date 2022-09-22 17:09:04
   * @returns {*}  {Promise<IData>}
   */
  abstract load(): Promise<IData>;

  /**
   * 获取表单数据
   *
   * @author lxm
   * @date 2022-08-30 19:08:11
   * @returns {*}
   */
  getData(): IData[] {
    return [this.state.data];
  }

  /**
   * 设置表单数据的值
   *
   * @author lxm
   * @date 2022-08-24 10:08:40
   * @param {string} name 要设置的表单数据的属性名称
   * @param {unknown} value 要设置的值
   */
  async setDataValue(name: string, value: unknown): Promise<void> {
    if (
      Object.prototype.hasOwnProperty.call(this.state.data, name) &&
      !isValueChange(this.state.data[name], value)
    ) {
      // *`表单里没有属性${name}或者${name}的值未发生改变`
      return;
    }

    // 改变值
    this.state.data[name] = value;

    // 设置正在处理状态
    this.state.processing = true;
    this.state.modified = true;

    await this._evt.emit('onFormDataChange', undefined);
    try {
      await this.dataChangeNotify([name]);
    } finally {
      this.state.processing = false;
    }
  }

  /**
   * 校验表单的全部表单项
   *
   * @author lxm
   * @date 2022-09-05 00:09:53
   * @returns {*}  {Promise<boolean>}
   */
  async validate(): Promise<boolean> {
    const values = await Promise.all(
      this.formItems.map(formItem => formItem.validate()),
    );

    // 找不到value为false即全部是true
    return values.findIndex(value => !value) === -1;
  }
}
